package com.okex.demo.service;

import com.okex.demo.model.PositionInfo;
import com.okex.demo.model.TickerInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.MessagingException;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * WebSocket推送服务
 * 负责数据推送到前端，包含重试机制和错误处理
 */
@Slf4j
@Service
public class WebSocketPushService {

    @Autowired
    private SimpMessagingTemplate messagingTemplate;
    
    private final ScheduledExecutorService retryExecutor = Executors.newSingleThreadScheduledExecutor();
    private static final int MAX_RETRY = 3;

    /**
     * 推送持仓信息
     * @param positions 持仓信息列表
     */
    public void pushPositions(List<PositionInfo> positions) {
        pushPositionsWithRetry(positions, 0);
    }
    
    /**
     * 带重试机制的持仓信息推送
     * 
     * @param positions 持仓信息列表
     * @param retryCount 当前重试次数
     */
    private void pushPositionsWithRetry(List<PositionInfo> positions, int retryCount) {
        try {
            // 确保每个持仓都有更新时间
            Date now = new Date();
            for (PositionInfo position : positions) {
                position.setUpdateTime(now);
            }
            
            messagingTemplate.convertAndSend("/topic/positions", positions);
            log.info("推送持仓信息，数量: {}, 时间: {}", positions.size(), now);
        } catch (MessagingException e) {
            handlePushError("持仓信息", e, retryCount, () -> pushPositionsWithRetry(positions, retryCount + 1));
        } catch (Exception e) {
            log.error("推送持仓信息异常: {}", e.getMessage(), e);
        }
    }

    /**
     * 推送行情信息
     * @param ticker 行情信息
     */
    public void pushTicker(TickerInfo ticker) {
        pushTickerWithRetry(ticker, 0);
    }
    
    /**
     * 带重试机制的行情信息推送
     * 
     * @param ticker 行情信息
     * @param retryCount 当前重试次数
     */
    private void pushTickerWithRetry(TickerInfo ticker, int retryCount) {
        try {
            if (ticker != null) {
                messagingTemplate.convertAndSend("/topic/ticker", ticker);
                log.info("推送行情信息: {}", ticker.getInstId());
            } else {
                log.warn("尝试推送空的行情信息");
            }
        } catch (MessagingException e) {
            String tickerId = ticker != null ? ticker.getInstId() : "unknown";
            handlePushError("行情信息 " + tickerId, e, retryCount, () -> pushTickerWithRetry(ticker, retryCount + 1));
        } catch (Exception e) {
            log.error("推送行情信息异常: {}", e.getMessage(), e);
        }
    }
    
    /**
     * 处理推送错误并实现重试逻辑
     * 
     * @param dataType 数据类型描述
     * @param e 异常
     * @param retryCount 当前重试次数
     * @param retryAction 重试动作
     */
    private void handlePushError(String dataType, Exception e, int retryCount, Runnable retryAction) {
        if (retryCount < MAX_RETRY) {
            int delaySeconds = (int) Math.pow(2, retryCount);
            log.warn("推送{}失败 (尝试 {}/{}), {} 秒后重试: {}", 
                    dataType, retryCount + 1, MAX_RETRY, delaySeconds, e.getMessage());
            
            retryExecutor.schedule(retryAction, delaySeconds, TimeUnit.SECONDS);
        } else {
            log.error("推送{}失败，已达到最大重试次数 {}: {}", 
                    dataType, MAX_RETRY, e.getMessage(), e);
        }
    }
} 